const redis = require("redis");


let dbclient, sub,pub;

//玩家位置
const USER_LOCATIONS = "userlocations"  

//正在创建的房间(还没有创建完的)
const ROOMING = "rooming";

//已经创建的房间
const ROOMS = "already_room";

//房间总数
const TOTAL_ROOM_NUM = "total_room_num";

const ROOM_IDS = "room_ids"

//亲友团
const CLUB = "club"

//游戏
const GAME = "game"

//座位
const SEATS = "seats"

//游戏局内座位
const GAME_SEATS = "game_seats";

const GAME_SEATS_USERS = "game_seat_user"

const OBSERVERS = "observers"

const USERS_ONLINE_SET = "users_online_set"

const DISS_ROOM = "diss_room"




/**
 * 初始化reids
 * @param {PORT:端口号,HOST:地址} config   
 */
function init(config){
    dbclient = redis.createClient(config);
    dbclient.on("error", function(err){
        console.log(err);
    })
   

    //清理操作
}

/**
 * 调用redis hexists方法
 * @param {*} key 
 * @return promise
 */
function hexists(mname, key) {
    return new Promise((resolve, reject) => {
        dbclient.hexists(mname, key, function(err, ret){
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(ret);
        });
    })
}
function lset(key ,index, str){
    return new Promise((reslove, reject) => {
        dbclient.lset(key, index, str, function(err, ret){
            if(err) {
                console.log(err);
                return reject(err)
            }
            reslove(ret);
        })
    })
}

/**
 * 调用redis incr方法
 * @param {*} key 
 * @return promise
 */
async function incr(key, num) {
    return new Promise((resolve, reject) => {
        dbclient.incr(key, function(err, ret){
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(ret);
        });
    })
}

/**
 * 调用redis hgetall方法
 * @param {*} mname 
 * @return promise
 */
function hgetall(mname){
    return new Promise((resolve, reject) => {
        dbclient.hgetall(mname, (err, ret) => {
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(ret);
        })
    })
}

/**
 * 调用redis lrange方法
 * @param {*} mname 
 * @return promise
 */
function lrange(lname, start, end) {
    return new Promise((reslove, reject) => {
        dbclient.lrange(lname, start, end, function(err, list){
            if(err) {
                console.log(err);
                return reject(err);
            }
            reslove(list);
        })
    })
}


/**
 * 调用redis hget方法
 * @param {*} mname 
 * @return promise
 */
function hget(mname, key){
    if(!key) return null;
    return new Promise((resolve, reject) => {
        dbclient.hget(mname, key, (err, ret) => {
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(ret);
        })
    })
}

function sadd(key, value) {
    return new Promise((resolve, reject) => {
        dbclient.sadd(key, value, (err) => {
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(null);
        })
    })
}

function sismember(key, value) {
    return new Promise((resolve, reject) => {
        dbclient.sismember(key, value, (err, ret) => {
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(ret);
        })
    })
}

function srem(key, value) {
    return new Promise((resolve, reject) => {
        dbclient.srem(key, value, (err) => {
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(null);
        })
    })
}
function lindex(key ,index) {
    return new Promise((resolve, reject) => {
        dbclient.lindex(key, index, (err, ret) => {
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(ret);
        })
    })
}
function smembers(key) {
    return new Promise((resolve, reject) => {
        dbclient.smembers(key, (err, ret) => {
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(ret);
        })
    })
}

function rpush(mname, list) {
    return new Promise((resolve, reject) => {
        dbclient.rpush(mname, ...list, function(err){
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(null);
        })
    })
}

function lpop(key){
    return new Promise((resolve, reject) => {
        dbclient.lpop(key, function(err,val){
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(val);
        })
    })
}

function llen(key){
    return new Promise((resolve, reject) => {
        dbclient.llen(key, function(err,val){
            if(err) {
                console.log(err);
                return reject(err);
            }
            resolve(val);
        })
    })
}

/**
 * 调用redis hmset方法
 * @param {*} mname 
 * @return promise
 */
function hmset(mname, key, value) {
    if(!key){
        return null;
    }
    return new Promise((reslove, reject) => {
        dbclient.hmset(mname, key, value, function(err) {
            if(err) {
                console.log(err);
                return reject(err)
            }
            reslove(null);
        })
    })
}

function hdel(mname, key) {
    return new Promise((reslove, reject) => {
        dbclient.hdel(mname, key, function(err) {
            if(err) {
                console.log(err);
                return reject(err)
            }
            reslove(null);
        })
    })
}
function get(key) {
    return new Promise((reslove, reject) => {
        dbclient.get(key, function(err,value) {
            if(err) {
                console.log(err);
                return reject(err)
            }
            reslove(value);
        })
    })
}

function set(key, value) {
    return new Promise((reslove, reject) => {
        dbclient.set(key,value, function(err) {
            if(err) {
                console.log(err);
                return reject(err)
            }
            reslove(null);
        })
    })
}

function del(key) {
    return new Promise((reslove, reject) => {
        dbclient.del(key, function(err) {
            if(err) {
                console.log(err);
                return reject(err)
            }
            reslove(null);
        })
    })
}

async function keys(key){
    return new Promise((reslove, reject) => {
        dbclient.keys(key, function(err, keys){
            if(err){
                return reject(err);
            }
            reslove(keys);
        })
    })
}

/**
 * 调用redis hmset方法
 * @param {*} mname 
 * @return promise
 */
function hmget(mname, key, value) {
    if(!mname || !key) {
        return null;
    }
    return new Promise((reslove, reject) => {
        dbclient.hmget(mname, key, function(err, ret) {
            if(err) {
                console.log(err);
                return reject(err)
            }
            reslove(ret);
        })
    })
}

/**
 * 调用redis hdel方法
 * @param {*} mname 
 * @return promise
 */
function hdel(mname, key) {
    return new Promise((reslove, reject) => {
        dbclient.hdel(mname, key, function(err) {
            if(err) {
                console.log(err);
                return reject(err)
            }
            reslove(null);
        })
    })
}

/**
 * 获取所有的用户位置
 * 用户数据放到 userlocations 集合里面
 * @return
 *    [{userId, roomId,seatIndex, mtime}]
 */
async function getUserLocations() {
    let ret = await hgetall(USER_LOCATIONS);
    return eachParseObj(ret);
}

/**
 * 获取指定的用户位置
 * @return
 *    {userId, roomId,seatIndex, mtime}
 */
async function getUserLocationById(userId) {
    let ret = await hget(USER_LOCATIONS, userId);
    if(ret) {
        return JSON.parse(ret)
    }
    return null;
}


/**
 * 由于redis值只能作为字符串的形式存储,如需存储对象需将对象转化为字符串的形式，此方法是对list字符串反转成json
 * @param {*} obj 
 */
function eachParseObj(obj) {
    for(let key in obj) {
        obj[key] = JSON.parse(obj[key])
    }
    return obj;
}

/**
 * 由于redis值只能作为字符串的形式存储,如需存储对象需将对象转化为字符串的形式，此方法是对list字符串反转成json
 * @param {*} obj 
 */
function eachParseList(list) {
    for(let i = 0; i < list.length; i++) {
        list[i] = JSON.parse(list[i])
    }
    return list;
}

/**
 * 写入人员位置信息
 * @param {*} location 
 *             roomId:  //房间id
 *			   seatIndex:-1,  //座位号
 *			   mtime:nowtime  //进入时间
 */
async function updateUserLocation(userId, location) {
    try{
        let dbloc = await getUserLocationById(userId);
        dbloc = dbloc || {};
        dbloc = inheritAttributes(dbloc, location)
        let lstr = JSON.stringify(dbloc);
        return hmset(USER_LOCATIONS, userId, lstr);
    }catch(err) {
        console.log(err);
        throw err;
    }
    
}

function removeUserLocation(userId) {
    try{
        return hdel(USER_LOCATIONS, userId);
    }catch(err) {
        console.log(err);
        throw err;
    }
}

async function setUserReady(roomId, userId, ready) {
    try{
        return updateSeatsAttribute(roomId, userId, {ready:ready});
    }catch(err) {
        console.log(err);
        throw err;
    }
}


/**
 * 写入亲友团信息
 * @param {*} clubId 
* @param {*} club
 */
async function saveClub(clubId, club) {
    try{
        let reqJoinUsers = club.reqJoinUsers || {};
        let members = club.members || {};
        let tables = club.tables || [];

        club.reqJoinUsers = null;
        club.members = null;
        club.tables = null;
        //reqJoinUsers 单独写入
        for(let userId in reqJoinUsers) {
            await updateClubJoinUser(clubId, userId, reqJoinUsers[userId]);
        }
        //merbers 单独写入
        for(let userId in members) {
            await updateClubMember(clubId, userId, members[userId])
        }
        //tables会在创建房间的时候写入
        // for(let i = 0; i < tables.length; i++) {
        //     let tab = tables[i];
        //     await saveRoom(tab.id, tab);
        // }

        // club.tds = tds;
        let lstr = JSON.stringify(club);

        //再写回去
        club.reqJoinUsers = reqJoinUsers;
        club.members = members;
        club.tables = tables;
        return hmset(CLUB, clubId, lstr);
    }catch(err){
        console.log(err);
        throw err;
    }
}

/**
 * 删除亲友团
 * @param {*} clubId 
 */
async function removeClub(clubId) {
    try{
        //获取基本信息
        let baseInfo = await hget(CLUB, clubId);
        if(!baseInfo) {
            return null;
        }
        baseInfo = JSON.parse(baseInfo)
        let tablesid = baseInfo.tablesid;
        if(typeof tablesid == "string") {
            tablesid = JSON.parse(baseInfo.tablesid || "[]");
        }
        await del(clubId+"_reqJoinUsers");;
        await del(clubId+"_members");
        // tablesid.forEach(async (tabid) => {
        //     await removeRoom(tabid);
        // })
        return hdel(CLUB, clubId);
    }catch(err) {
        console.log(err);
        throw err;
    }
   
}

async function updateClub(clubId, updates){
    //获取基本信息
    let baseInfo = await hget(CLUB, clubId);
    if(!baseInfo) {
        return null;
    }
    baseInfo = JSON.parse(baseInfo)
    inheritAttributes(baseInfo, updates);
    return hmset(CLUB,clubId, JSON.stringify(baseInfo));
}

async function setClubName(clubId, name) {
    try{
        //获取基本信息
        let baseInfo = await hget(CLUB, clubId);
        if(!baseInfo) {
            return null;
        }
        baseInfo = JSON.parse(baseInfo);
        baseInfo.name = name;
        return hmset(CLUB, clubId, JSON.stringify(baseInfo));
    }catch(err) {
        console.log(err);
        throw err;
    }
}
/**
 * 获取亲友团
 * @club   亲友团Id
 * @return
 *    
 */
async function getClubById(clubId) {
    try{
        //获取基本信息
        let baseInfo = await hget(CLUB, clubId);
        if(!baseInfo) {
            return null;
        }
        baseInfo = JSON.parse(baseInfo);
        let reqJoinUsers = await hgetall(clubId+"_reqJoinUsers") || {};
        reqJoinUsers = eachParseObj(reqJoinUsers);
        let members = await hgetall(clubId+"_members") || {};
        members = eachParseObj(members);
        let tablesid = baseInfo.tablesid;
        let tableList = [];
        for(let i = 0; i < tablesid.length; i++) {
            let tabid = tablesid[i];
            let room = await getRoomById(tabid)
            tableList.push(room);
        }
        baseInfo.tablesid = JSON.stringify(baseInfo.tablesid);
        Object.assign(baseInfo, {
            reqJoinUsers,
            members,
            tables : tableList
        })
        return baseInfo;
    }catch(err) {
        console.log(err);
        throw err;
    }
}



/**
 * 
 * @param {*} clubId 
 * @param {*} userId 
 * @param {*} data 
 */
function updateClubJoinUser(clubId, userId, data) {
    try{
        return hmset(clubId+"_reqJoinUsers", userId, JSON.stringify(data))
    }catch(err) {
        console.log(err);
        throw err;
    }
}

function removeClubUser(clubId, userId) {
    try{
        return hdel(clubId+"_reqJoinUsers", userId)
    }catch(err) {
        console.log(err)
        throw err;
    }
}

function removeClubMember(clubId, userId) {
    try{
        return hdel(clubId+"_members", userId)
    }catch(err) {
        console.log(err);
        throw err;
    }
}

/**
 * 
 * @param {*} clubId 
 * @param {*} userId 
 * @param {*} data 
 */
function updateClubMember(clubId, userId, data) {
    try{
        return hmset(clubId+"_members", userId, JSON.stringify(data));
    }catch(err) {
        console.log(err);
        throw err;
    }
}

async function updateClubConf(clubId, conf) {
    try{
        let clubInfo = await hget(CLUB, clubId);
        if(!clubInfo) return;
        clubInfo = JSON.parse(clubInfo);
        clubInfo.club_conf = conf;
        return hmset(CLUB, clubId, JSON.stringify(clubInfo));
    }catch(err) {
        console.log(err);
        throw err;
    }
}

async function updateClubMemberState(clubId, userId, state) {
    try{
        let member = await hget(clubId+"_members", userId);
        if(!member){
            return;
        }
        member = JSON.parse(member || "{}");
        member.state = state;
        return updateClubMember(clubId, userId, member);
    }catch(err) {
        console.log(err);
        throw err;
    }
}

/**
 * 修改房间座位的属性
 * @param {*} roomId 房间id
 * @param {*} userId  用户id
 * @param {*} attributes  要修改的属性 如{score:2};
 */
async function updateSeatsAttribute(roomId, userId, attributes,seatIndex) {
    try{
        //如果传了座位号
        if(seatIndex || seatIndex == 0) {
            userSeat = await lindex(SEATS+"_"+roomId, seatIndex);
            userSeat = userSeat || "{}";
            userSeat = JSON.parse(userSeat);
            userSeat = inheritAttributes(userSeat, attributes)
            userSeat.userId = userId;
            return lset(SEATS+"_"+roomId, seatIndex, JSON.stringify(userSeat));
        }else {
            let seats = await lrange(SEATS+"_"+roomId, 0, -1);
            seats = eachParseList(seats);
            let index, userSeat;
            for(let i = 0; i < seats.length; i++) {
                let seat = seats[i];
                if(seat.userId == userId) {
                    index = i;
                    userSeat = seat;
                    break;
                }
            }
            if(userSeat) {
                userSeat = inheritAttributes(userSeat, attributes);
                userSeat = JSON.stringify(userSeat);
                return lset(SEATS+"_"+roomId, index, userSeat);
            }
        }
    }catch(err) {
        console.log(err)
        throw err;
    }
}

async function updateUserState(userId, state) {
    try{
        return hmset("user_state", userId, state);
    }catch(err){
        console.log(err)
        throw err;
    }
}

async function setUserLogin(userId, isLogin) {
    try{
        isLogin = isLogin ? 1: 0;
        return hmset("user_login", userId, isLogin);
    }catch(err){
        console.log(err)
        throw err;
    }
}

async function incConnectNum(userId) {
    try{
        let connectNum = await hmget("connect_num", userId);
        connectNum = +connectNum || 0
        return await hmset("connect_num", userId, ++connectNum)
    }catch(err){
        console.log(err)
        throw err;
    }
}

async function getConnectNum(userId) {
    try{
        let connectNum = await hmget("connect_num", userId);
        connectNum = +connectNum || 0
        return connectNum    
    }catch(err){
        console.log(err)
        throw err;
    }
    
}
async function clearConnectNum(userId){
    try{
        return await hmset("connect_num", userId, 0)
    }catch(err){
        console.log(err)
        throw err;
    }
}
async function clearDisconnectNum(userId){
    try{
        return await hmset("disconnect_num", userId, 0)
    }catch(err){
        console.log(err)
        throw err;
    }
}
async function incDisconnectNum(userId) {
    try{
        let connectNum = await hmget("disconnect_num", userId);
        connectNum = +connectNum || 0
        return await hmset("disconnect_num", userId, ++connectNum)
    }catch(err){
        console.log(err)
        throw err;
    }
}

async function getDisconnectNum(userId) {
    try{
        var connectNum = await hmget("disconnect_num", userId);
        return +connectNum || 0;
    }catch(err){
        console.log(err);
        throw err
    }
}

async function getUserLogin(userId) {
    try{
        var login = await hmget("user_login", userId);
        return +login || 0
    }catch(err){
        console.log(err)
        throw err;
    }
}

async function getUserState(userId) {
    try{
        let state = await hmget("user_state", userId);
        state = +state || 0;
        return state;
    }catch(err){
        console.log(err)
        throw err;
    }
}

async function updateGameSeatByIndex(roomId, index, data) {
    try{
        let gameSeat = await lindex(GAME_SEATS+"_"+roomId, index);
        if(!gameSeat) {
            return null;
        }
        var initGame = null;
        if(data["$rep"] && data["$rep"].game) {
            initGame = data["$rep"].game;
            data["$rep"].game = null;
        }
        gameSeat = JSON.parse(gameSeat);
        gameSeat = inheritAttributes(gameSeat, data);
        if(initGame){
            data["$rep"].game = initGame;
        }
        return lset(GAME_SEATS+"_"+roomId, index, JSON.stringify(gameSeat));
    }catch(err) {
        console.log(err);
        throw err;
    }
}

/**
 * 属性深度继承
 * @param {*} attrs1 
 * @param {*} attrs2 
 */
function inheritAttributes(attrs1, attrs2){
    try{
        for(var key in attrs2) {
            if(key == "$inc") { //如果是自增操作
                for(var incKey in attrs2[key]) {
                    attrs1[incKey] = attrs1[incKey] || 0;
                    attrs1[incKey] += attrs2[key][incKey]
                }
                continue;
            }
            if(key == "$null") {  //置空
                for(var incKey in attrs2[key]) {
                    attrs1[incKey] = null;
                }
                continue;
            }
            if(key == "$rep") { //替换
                for(var incKey in attrs2[key]) {
                    attrs1[incKey] = attrs2[key][incKey];
                }
                continue;
            }
            if(typeof attrs2[key] == "object") {
                if(!attrs1[key]) {
                    attrs1[key] = {};
                }
                inheritAttributes(attrs1[key], attrs2[key]);
            }else {
                attrs1[key] = attrs2[key];
            }
        }
        return attrs1;
    }catch(err) {
        console.log(err);
        throw err;
    }
}
function multi(arr) {
    try{
        new Promise((reslove, reject) => {
            dbclient.multi(arr).exec(function(err){
                if(err){
                    return reject(err)
                }
                reslove(null);
            })
        })
    }catch(err){

    }
}

/**
 * 保存房间
 * @param {*} roomId 
 * @param {*} data 
 */
async function saveRoom(roomId, data) {
    try{
        let seats = data.seats || [];
        let observers = data.observers || [];
        seats.forEach( (element,index) => {
            if(typeof element !="string"){
                element = JSON.stringify(element);
            }
            seats[index] = element;
        });
        data.seats = null;
        data.observers = null;
        await multi([
            ["del",SEATS+"_"+roomId],
            ["rpush",SEATS+"_"+roomId, seats]
        ]);
        // await del(SEATS+"_"+roomId);
        // await rpush(SEATS+"_"+roomId, seats)
        await hmset(ROOMS, roomId, JSON.stringify(data));
        seats.forEach( (element,index) => {
            seats[index] = JSON.parse(element)
        });
        data.seats = seats;
        data.observers = observers;
        //写入房间ids
        if(!data.club_id){
            await sadd(ROOM_IDS, roomId);
        }
        // await sadd(ROOM_IDS, roomId);
    }catch(err) {
        console.log(err);
        throw err;
    }
    //写入observers
    //...
}

/**
 * 删除房间
 * @param {*} roomId 
 */
async function removeRoom(roomId) {
    try{
        await del(SEATS+"_"+roomId);
        await hdel(ROOMS, roomId);
        await srem(ROOM_IDS, roomId);  //删除room_ids 里面的roomid
    }catch(err) {
        console.log(err);
        throw err;
    }
}

async function getAllRoomIds() {
    // await sadd(ROOM_IDS, 123455)
    try{
        return smembers(ROOM_IDS)
    }catch(err) {
        console.log(err);
        throw err;
    }
}

/**
 * 获取房间信息
 * @param {*} roomId 
 * @param {*} baseFlag 是否只查询roomInfo
 */
async function getRoomById(roomId, baseFlag){
    try{
        //获取房间基本信息
        let roomInfo = await hget(ROOMS, roomId);
        if(!roomInfo) {
            return null
        }
        roomInfo = JSON.parse(roomInfo)
        if(!baseFlag) {
            //获取房间座次信息
            let seats = await lrange(SEATS+"_"+roomId, 0, -1);
            roomInfo.seats = eachParseList(seats);
            let observers = await smembers(OBSERVERS+"_"+roomId);
            roomInfo.observers = observers;
        }
        return roomInfo;
    }catch(err) {
        console.log(err);
        throw err;
    }
}

async function pushRoomObUser(roomId, userId) {
    try{
        return sadd(OBSERVERS+"_"+roomId, userId);
    }catch(err) {
        console.log(err);
        throw err;
    }
}


async function removeRoomObUser(roomId, userId) {
    try{
        return srem(OBSERVERS+"_"+roomId, userId);
    }catch(err) {
        console.log(err);
        throw err;
    }
}

async function clearObservers(roomId) {
    try{
        return del(OBSERVERS+"_"+roomId);
    }catch(err) {
        console.log(err);
        throw err;
    }
}


/**
 * 记录正在创建的房间(未创建完成)
 * @param {*} roomId 房间id
 */
function pushRomming(roomId) {
    try{
        return hmset(ROOMING, roomId, 1);
    }catch(err) {
        console.log(err);
        throw err;
    }
}

/**
 * 删除正在创建的房间(创建完成后删除)
 * @param {*} roomId 房间id
 */
function removeRooming(roomId) {
    try{
        return hdel(ROOMING, roomId);
    }catch(err) {
        console.log(err);
        throw err;
    }
}


/**
 * 检查房间号是否处于正在创建的过程中
 * @param {*} roomId 房间id
 */
async function checkRooming(roomId) {
    try{
        let rooming = await hexists(ROOMING, roomId);
        return !!rooming;
    }catch(err) {
        console.log(err);
        throw err;
    }
}


/**
 * 检查房间号是否被占用
 * @param {*} roomId 房间id
 */
async function checkRoomExist(roomId) {
    try{
        let exist = await hexists(ROOMS, roomId);
        return !!exist;
    }catch(err) {
        console.log(err);
        throw err;
    }
}

/**
 * 修改房间基本信息
 * @param {} roomId 
 * @param {*} updates 
 */
async function updateRoomInfo(roomId, updates) {
    try{
        let roomInfo = await hget(ROOMS, roomId);
        if(roomInfo) {
            roomInfo = JSON.parse(roomInfo);
            roomInfo = inheritAttributes(roomInfo, updates)
            if(roomInfo.seats) {
                delete roomInfo.seats
            }
            return hmset(ROOMS, roomId, JSON.stringify(roomInfo));
        }
    }catch(err){
        console.log(err);
        throw err;
    }
}

/**
 * 
 * @param {*} inc 增加数量(默认为1)
 */
function incTotalRooms(num) {
    try{
        num = num || 1
        return incr(TOTAL_ROOM_NUM, num);
    }catch(err){
        console.log(err);
        throw err;
    }
}

async function getTotalRooms() {
    try{
        return get(TOTAL_ROOM_NUM);
    }catch(err){
        console.log(err);
        throw err;
    }
    
}

//在线人员开始
function pushUserOnline(userId) {
    try{
        return sadd(USERS_ONLINE_SET, userId)
    }catch(err){
        console.log(err);
        throw err;
    }
}

function pushDissolving(roomId) {
    try{
        return sadd(DISS_ROOM, roomId)
    }catch(err){
        console.log(err);
        throw err;
    }
}

async function getDissolving(){
    try{
        return smembers(DISS_ROOM)
    }catch(err){
        console.log(err);
        throw err;
    }
}

async function isOnline(userId) {
    try{
        return sismember(USERS_ONLINE_SET, userId);
    }catch(err){
        console.log(err);
        throw err;
    }
    
}
async function onlineNumber(){
    try{
        let list = await smembers(USERS_ONLINE_SET);
        return list.length;
    }catch(err){
        console.log(err);
        throw err;
    }
    
}
function removeUserOnline(userId) {
    try{
        return srem(USERS_ONLINE_SET, userId);
    }catch(err){
        console.log(err);
        throw err;
    }
    
}



//在线人员结束


function removeDissolving(roomId){
    try{
        return srem(DISS_ROOM, roomId);
    }catch(err){
        console.log(err);
        throw err;
    }
    
}




/**
 * 保存游戏
 * @param {*} roomId 
 * @param {*} data 
 */
async function saveGame(roomId, data) {
    try{
        let seats = data.gameSeats || [];
        seats.forEach( (element,index) => {
            var seatGame = element.game;
            let str = JSON.stringify(element);
            seats[index] = str;
            element.game = seatGame;
        });
        delete data.gameSeats;
        data.roomId = roomId;
        await del(GAME_SEATS+"_"+roomId)
        await rpush(GAME_SEATS+"_"+roomId, seats)
        await hmset(GAME, roomId, JSON.stringify(data));
        eachParseList(seats)
        data.gameSeats = seats;
    }catch(err){
        console.log(err);
        throw err;
    }
}


/**
 * 保存游戏
 * @param {*} roomId 
 * @param {*} data 
 */
async function getGameByRoomId(roomId, baseFlag) {
    try{
        //获取房间基本信息
        let gameInfo = await hget(GAME, roomId);
        if(!gameInfo) {
            return null
        }
        gameInfo = JSON.parse(gameInfo)
        if(!baseFlag) {
            //获取房间信息
            // let roomInfo = await getRoomById(roomId);
            // // gameInfo.roomInfo = roomInfo;
            // gameInfo.conf = (roomInfo ||{}).conf;
            //获取房间座次信息
            let seats = await lrange(GAME_SEATS+"_"+roomId, 0, -1);
            gameInfo.gameSeats = eachParseList(seats);
        }
        return gameInfo;
    }catch(err){
        console.log(err);
        throw err;
    }
}

async function removeGameByRoomId(roomId) {
    try{
        await del(GAME_SEATS+"_"+roomId);
        await hdel(GAME, roomId);
    }catch(err){
        console.log(err);
        throw err;
    }
}

/**
 * 修改游戏信息
 * @param {*} roomId 
 * @param {*} updates 
 */
async function updateGameByRoomId(roomId, updates) {
    try{
        //获取房间基本信息
        let gameInfo = await hget(GAME, roomId);
        if(!gameInfo) {
            return;
        }
        gameInfo = JSON.parse(gameInfo);
        gameInfo = inheritAttributes(gameInfo, updates)
        return hmset(GAME, roomId, JSON.stringify(gameInfo));
    }catch(err) {
        console.log(err);
        throw err;
    }
}


/**
 * 获取用户游戏局内信息
 * @param {*} userId 
 */
async function getGameSeatsByUserId(userId) {
    try{
        //获取用户所在的房间
        let location = await getUserLocationById(userId);
        if(!location) {
            return null;
        }
        let roomId = location.roomId;
        let seatIndex = location.seatIndex;
        let seatData = await lindex(GAME_SEATS+"_"+roomId, seatIndex);
        if(!seatData) {
            return null;
        }
        seatData = JSON.parse(seatData);
        //获取座位游戏信息
        let gameInfo = await getGameByRoomId(roomId);
        if(!gameInfo) {
            return null;
        }
        seatData.game = gameInfo;
        return seatData;
    }catch(err){
        console.log(err);
        throw err;
    }
}

async function getGameSeatsOfUsers(roomId, baseFlag) {
    try{
        var returnList = [];
        let seatDataList = await lrange(GAME_SEATS+"_"+roomId, 0, -1);
        let gameInfo = await getGameByRoomId(roomId);
        seatDataList = eachParseList(seatDataList);
        seatDataList.forEach((element) => {
            if(!baseFlag) {
                element.game = gameInfo;
            }
            if(element.userId>0) {
                returnList.push(element);
            }
        })
        return returnList;
    }catch(err){
        console.log(err);
        throw err;
    }
}

async function lock(key, state) {
    try{
        if(state !== true && state!== false) {
            var state = await hget("lock", key);
            return state == "1" ? true : false; //0为非锁定状态，1
        }
        state = state ===true ? "1" : "0";   //1锁定 0非锁定
        if(state == "0"){
            return hdel("lock", key);
        }else {
            return hmset("lock", key, state);
        }
    }catch(err){
        console.log(err);
        throw err;
    }
}

async function pushMessage(userId, obj){
    return rpush("message_"+userId,[JSON.stringify(obj)])
}

async function getMessages(userId, obj){
    let list = await lrange("message_"+userId, 0, -1);
    await del("message_"+userId);
    list = eachParseList(list)
    return list;
}

async function setUserLoginTime(userId) {
    await hmset("user_login_time", userId, Date.now())
}

async function getUserLoginTime(userId) {
    var loginTime = await hmget("user_login_time", userId)
    loginTime = +loginTime || 0;
    return loginTime
}


async function setUserBeatTime(userId) {
    return hmset("ubt",userId, Date.now());
}
async function getAllUserBeatTime(userId) {
    return hgetall("ubt", userId);
}

async function delUserBetTime(userId){
    return hdel("ubt", userId)
}

async function bindIp(userId, ip){
    return hmset("socketIp",userId, ip);
}
async function getSocketIp(userId){
    return hmget("socketIp", userId);
}

async function saveGameHistory(game){
    return rpush("z_game_"+game.roomId+"_"+game.conf.createTime, [JSON.stringify(game)])
}

async function roomLock(roomId){
    return incr("room_lock_"+roomId, 1)
}

async function getRoomLock(roomId) {
    return get("room_lock_"+roomId)
}

async function removeRoomLock(roomId){
    return del("room_lock_"+roomId);
}




module.exports = {
    init,    //初始化
    getUserLocations,  //获取所有的玩家位置
    getUserLocationById, //根据用户ID获取玩家位置
    updateUserLocation,   //写入/修改玩家位置
    removeUserLocation, //删除用户位置
    pushRomming,  //记录正在创建的房间(未创建完成)
    removeRoom, //删除房间
    removeRooming,  //删除正在创建的房间(创建完成后删除)
    checkRooming,  //检查房间号是否处于正在创建的过程中
    checkRoomExist,   //检查房间是否被占用
    updateRoomInfo,  //
    getAllRoomIds,
    saveRoom,  //写入房间
    getRoomById,  //获取房间
    pushRoomObUser,  //添加人员至旁观者
    removeRoomObUser,  //从旁观者移除
    clearObservers, //清空旁观者
    incTotalRooms,  //总房间数+1;
    getTotalRooms,  //获取总房间数
    
    //在线人员开始
    removeUserOnline,  //移除在线用户
    pushUserOnline,    //添加在线用户
    isOnline,   //判断这个用户是否在线
    onlineNumber, //在线人数
    //在线人员结束
    
    //亲友团开始
    getClubById, //根据用户ID获取玩家位置
    saveClub,   //保存亲友团
    removeClub,  //删除亲友团
    updateClub, //跟新亲友圈
    removeClubUser,  //删除亲友团的申请
    removeClubMember, //删除亲友团的成员
    updateClubJoinUser,  //修改/写入玩家申请亲友团
    updateClubMemberState,   //更新亲友团玩家状态
    updateClubMember,  //
    updateClubConf,  //更改俱乐部的配置
    setClubName, //修改亲友团名字
    //亲友团结束



    setUserReady,  //修改用户准备状态
    
    updateSeatsAttribute, //修改房间座位的属性
    updateUserState,  //修改用户状态
    getUserState,   //获取用户在线状态
    saveGame, //保存游戏
    getGameByRoomId,//获取游戏
    updateGameByRoomId, //修改游戏配置
    removeGameByRoomId,  //删除游戏
    getGameSeatsByUserId, //根据用户id获取游戏座次
    updateGameSeatByIndex, //修改游戏座次
    getGameSeatsOfUsers,   //获取所有已经坐满的游戏座位
    
    //解散房间
    pushDissolving,  //添加正在请求解散的房间
    getDissolving,   //获取正在结算的房间
    removeDissolving,  //删除正在解散的房间
    setUserBeatTime,   //设置用户心跳时间
    getAllUserBeatTime,   //获取用户心跳时间
    delUserBetTime,
    saveGameHistory,

    lock,
    pushMessage, 
    getMessages,
    rpush,
    llen,
    lpop,
    setUserLogin,
    getUserLogin,
    keys,
    setUserLoginTime,
    getUserLoginTime,
    bindIp,
    getSocketIp,
    keys,
    del,
    roomLock,
    removeRoomLock,
    getRoomLock
}




